package com.example.demo;

import com.example.dao.UserDao;
import com.example.model.User;
import com.example.service.AuthService;

/**
 * Mockito演示类
 * 展示Mockito的基本使用方法和测试技巧
 */
public class MockitoDemo {

    public static void main(String[] args) {
        MockitoDemo demo = new MockitoDemo();

        System.out.println("=== Mockito 基本概念演示 ===");
        demo.demonstrateBasicConcepts();

        System.out.println("\n=== Mockito 实际应用演示 ===");
        demo.demonstrateRealWorldUsage();

        System.out.println("\n=== Mockito 高级特性演示 ===");
        demo.demonstrateAdvancedFeatures();
    }

    /**
     * 演示Mockito的基本概念
     */
    public void demonstrateBasicConcepts() {
        System.out.println("1. Mock对象的概念：");
        System.out.println("   - Mock对象是真实对象的替代品");
        System.out.println("   - 可以控制Mock对象的行为");
        System.out.println("   - 可以验证Mock对象的方法调用");

        System.out.println("\n2. 为什么使用Mock：");
        System.out.println("   - 隔离被测试的代码");
        System.out.println("   - 避免外部依赖（如数据库、网络）");
        System.out.println("   - 提高测试速度");
        System.out.println("   - 测试异常情况");

        System.out.println("\n3. Mockito的核心注解：");
        System.out.println("   - @Mock：创建Mock对象");
        System.out.println("   - @InjectMocks：将Mock注入到被测类");
        System.out.println("   - @ExtendWith(MockitoExtension.class)：启用Mockito");
    }

    /**
     * 演示实际应用场景
     */
    public void demonstrateRealWorldUsage() {
        System.out.println("演示业务逻辑测试场景：");

        // 模拟场景：测试用户登录功能
        System.out.println("\n场景1：测试用户登录成功");
        demonstrateLoginSuccess();

        System.out.println("\n场景2：测试用户登录失败");
        demonstrateLoginFailure();

        System.out.println("\n场景3：测试用户注册功能");
        demonstrateUserRegistration();
    }

    /**
     * 演示登录成功场景
     */
    private void demonstrateLoginSuccess() {
        System.out.println("  测试用例：用户使用正确密码登录");

        // 创建测试数据
        User testUser = new User(1, "alice", "123456", "alice@example.com");

        // 模拟UserDao的行为
        // 注意：这里只是演示概念，实际测试中需要使用@Mock注解
        System.out.println("  - 模拟UserDao.findByUsername('alice')返回用户对象");
        System.out.println("  - 调用AuthService.authenticate('alice', '123456')");
        System.out.println("  - 验证返回true");
        System.out.println("  - 验证UserDao.findByUsername被调用");

        System.out.println("  ✓ 测试通过：登录成功");
    }

    /**
     * 演示登录失败场景
     */
    private void demonstrateLoginFailure() {
        System.out.println("  测试用例：用户使用错误密码登录");

        // 创建测试数据
        User testUser = new User(1, "alice", "123456", "alice@example.com");

        System.out.println("  - 模拟UserDao.findByUsername('alice')返回用户对象");
        System.out.println("  - 调用AuthService.authenticate('alice', 'wrongpassword')");
        System.out.println("  - 验证返回false");
        System.out.println("  - 验证UserDao.findByUsername被调用");

        System.out.println("  ✓ 测试通过：登录失败");
    }

    /**
     * 演示用户注册场景
     */
    private void demonstrateUserRegistration() {
        System.out.println("  测试用例：注册新用户");

        System.out.println("  - 模拟UserDao.findByUsername('newuser')返回null（用户不存在）");
        System.out.println("  - 模拟UserDao.saveUser()成功执行");
        System.out.println("  - 调用AuthService.register('newuser', 'password123', 'newuser@example.com')");
        System.out.println("  - 验证返回true");
        System.out.println("  - 验证UserDao.findByUsername被调用");
        System.out.println("  - 验证UserDao.saveUser被调用");

        System.out.println("  ✓ 测试通过：注册成功");
    }

    /**
     * 演示高级特性
     */
    public void demonstrateAdvancedFeatures() {
        System.out.println("1. 参数匹配器：");
        System.out.println("   - any()：匹配任何参数");
        System.out.println("   - anyString()：匹配任何字符串");
        System.out.println("   - anyInt()：匹配任何整数");
        System.out.println("   - eq()：精确匹配参数");

        System.out.println("\n2. 验证方法调用：");
        System.out.println("   - verify(mock).method()：验证方法被调用");
        System.out.println("   - verify(mock, times(n)).method()：验证方法被调用n次");
        System.out.println("   - verify(mock, never()).method()：验证方法从未被调用");
        System.out.println("   - verify(mock, atLeastOnce()).method()：验证方法至少被调用一次");

        System.out.println("\n3. 异常测试：");
        System.out.println("   - when(mock.method()).thenThrow(new Exception())：模拟异常");
        System.out.println("   - 测试代码对异常的处理");

        System.out.println("\n4. 链式调用：");
        System.out.println("   - when(mock.method()).thenReturn(value1).thenReturn(value2)");
        System.out.println("   - 模拟方法多次调用返回不同值");
    }

    /**
     * 演示测试代码结构
     */
    public void demonstrateTestStructure() {
        System.out.println("典型的Mockito测试类结构：");

        System.out.println("\n```java");
        System.out.println("@ExtendWith(MockitoExtension.class)");
        System.out.println("public class AuthServiceTest {");
        System.out.println("    @Mock");
        System.out.println("    private UserDao userDao;");
        System.out.println("    ");
        System.out.println("    @InjectMocks");
        System.out.println("    private AuthService authService;");
        System.out.println("    ");
        System.out.println("    @Test");
        System.out.println("    void testAuthenticate() {");
        System.out.println("        // 准备测试数据");
        System.out.println("        User user = new User(1, \"alice\", \"123\");");
        System.out.println("        when(userDao.findByUsername(\"alice\")).thenReturn(user);");
        System.out.println("        ");
        System.out.println("        // 执行测试");
        System.out.println("        boolean result = authService.authenticate(\"alice\", \"123\");");
        System.out.println("        ");
        System.out.println("        // 验证结果");
        System.out.println("        assertTrue(result);");
        System.out.println("        verify(userDao).findByUsername(\"alice\");");
        System.out.println("    }");
        System.out.println("}");
        System.out.println("```");
    }

    /**
     * 演示最佳实践
     */
    public void demonstrateBestPractices() {
        System.out.println("Mockito使用的最佳实践：");

        System.out.println("\n1. 测试命名：");
        System.out.println("   - 使用描述性的测试方法名");
        System.out.println("   - 格式：test[方法名]_[场景]_[期望结果]");
        System.out.println("   - 例如：testAuthenticate_ValidCredentials_ReturnsTrue");

        System.out.println("\n2. 测试结构（AAA模式）：");
        System.out.println("   - Arrange：准备测试数据和Mock行为");
        System.out.println("   - Act：执行被测试的方法");
        System.out.println("   - Assert：验证结果和Mock调用");

        System.out.println("\n3. Mock使用原则：");
        System.out.println("   - 只Mock外部依赖，不Mock被测试的类");
        System.out.println("   - 使用接口而不是具体实现");
        System.out.println("   - 避免过度Mock，保持测试的简单性");

        System.out.println("\n4. 验证原则：");
        System.out.println("   - 验证业务逻辑，而不仅仅是方法调用");
        System.out.println("   - 验证重要的交互，避免过度验证");
        System.out.println("   - 使用有意义的断言消息");
    }
}